package z.t.b.db.compare.ddl;

import org.apache.commons.lang3.StringUtils;
import z.t.b.db.meta.Column;
import z.t.b.db.meta.DB;
import z.t.b.db.meta.Index;
import z.t.b.db.meta.Table;
import z.t.b.db.utils.StrUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * xx
 *
 * @Description TODO
 * @Author ztb
 * @Date 2024/3/23 19:10
 * @Version 1.0
 */
public class DDLCompare {

    private DB srcDB;
    private DB tarDB;

    private List<String> changeSqlList = new ArrayList<>();

    public DDLCompare(DB srcDB, DB tarDB) {
        this.srcDB = srcDB;
        this.tarDB = tarDB;
    }

    public void doCompare(){
        for(Table srcTable : srcDB.getTables().values()){
            // 不存在就创建
            Table tarTable = tarDB.getTable(srcTable.getTableName());
            if(tarTable == null){
                changeSqlList.add(srcTable.getCreateDDL());
                continue;
            }
            // 存在就比较
            compareTable(srcTable, tarTable);
            compareKeys(srcTable, tarTable);
        }
    }

    /**
     *
     * @param srcTable
     * @param tarTable
     */
    private void compareTable(Table srcTable, Table tarTable) {
        String after = null;
        List<String> changeList = new ArrayList<>();
        for (Column column : srcTable.getColumns().values()) {
            if (tarTable.getColumns().get(column.getName()) == null) {
                // 如果对应的target没有这个字段,直接alter
                String sql = "alter table " + tarTable.getTableSchema() + "." + tarTable.getTableName() + " add " + column
                        .getName() + " ";
                sql += column.getType() + " ";
                if (column.getIsNull().equals("NO")) {
                    sql += "NOT NULL ";
                } else {
                    sql += "NULL ";
                }
                if (column.getDefaultValue() != null) {
                    sql += "DEFAULT " + StrUtils.getDbString(column.getDefaultValue()) + " ";
                }
                if (column.getComment() != null) {
                    sql += "COMMENT " + StrUtils.getDbString(column.getComment()) + " ";
                }
                if (after != null) {
                    sql += "after " + after;
                }
                changeList.add(sql+";\n");
            } else {
                // 检查对应的source 和 target的属性
                String sql =
                        "alter table " + tarTable.getTableSchema() + "." + tarTable.getTableName() + " change " + column
                                .getName() + " ";
                Column sourceColumn = column;
                Column targetColumn = tarTable.getColumns().get(sourceColumn.getName());
                // 比较两者字段,如果返回null,表明一致
                String sqlExtend = compareColumn(sourceColumn, targetColumn);
                if (sqlExtend != null) {
                    changeList.add(sql + sqlExtend);
                }
            }
            after = column.getName();
        }

        /*// remove the target redundancy columns
        for (Column column : tarTable.getColumns().values()) {
            if (srcTable.getColumns().get(column.getName()) == null) {
                // drop it
                String sql = "alter table " + tarTable.getTableSchema() + "." + tarTable.getTableName() + " drop " + column
                        .getName() + " ";
                changeList.add(sql);
            }
        }*/
        // 视图如果有差异就执行重建
        if(changeList.size()>0){
            if(Table._TYPE_VIEW.equals(srcTable.getObjectType())){
                changeSqlList.add(srcTable.getCreateDDL());
            }else{
                changeSqlList.addAll(changeList);
            }
        }
    }

    /**
     *
     * @param srcColumn
     * @param tarColumn
     * @return
     */
    private String compareColumn(Column srcColumn, Column tarColumn) {
        List<String> modify = new ArrayList<String>();
        if (srcColumn.equals(tarColumn)) {
            return null;
        }
        String changeSql = "";
        if (!srcColumn.getName().equals(tarColumn.getName())) {
            // never reach here
            throw new RuntimeException("the bug in this tool");
        }
        changeSql += srcColumn.getName() + " ";
        changeSql += srcColumn.getType() + " ";
        if (srcColumn.getIsNull().equals("NO")) {
            changeSql += "NOT NULL ";
        } else {
            changeSql += "NULL ";
        }
        if (srcColumn.getExtra().toUpperCase().indexOf("AUTO_INCREMENT") != -1) {
            changeSql += "AUTO_INCREMENT ";
        }
        if (StringUtils.isNotBlank(srcColumn.getDefaultValue())) {
            changeSql += "DEFAULT " + srcColumn.getDefaultValue() + " ";
        }
        if (StringUtils.isNotBlank(srcColumn.getComment())) {
            changeSql += "COMMENT " + StrUtils.getDbString(srcColumn.getComment()) + " ";
        }
        return changeSql;
    }

    /**
     * 索引比较
     * @param srcTable
     * @param tarTable
     */
    private void compareKeys(Table srcTable, Table tarTable) {
        for (Index index : srcTable.getIndexes().values()) {
            String sql = "alter table " + tarTable.getTableSchema() + "." + tarTable.getTableName() + " ";
            if (tarTable.getIndexes().get(index.getIndexName()) == null) {
                if (index.getIndexName().equals("PRIMARY")) {
                    sql += "add primary key ";
                } else {
                    if (index.getNotUnique().equals("0")) {
                        sql += "add unique "+index.getIndexName()+" ";
                    } else {
                        sql += "add index "+index.getIndexName()+" ";
                    }
                }
                sql += "(`";
                for (String key : index.getColumns()) {
                    sql += key.trim() + "`,`";
                }
                // 去掉最后一个,`
                sql = sql.substring(0, sql.length() - 2) + ")";
                changeSqlList.add(sql);
            }
        }
        for (Index index : tarTable.getIndexes().values()) {
            if (srcTable.getIndexes().get(index.getIndexName()) == null) {
                // 表明此索引多余
                String sql = "alter table " + tarTable.getTableSchema() + "." + tarTable.getTableName() + " ";
                if (index.getIndexName().equals("PRIMARY")) {
                    sql += "drop primary key ";
                } else {
                    sql += "drop index " + index.getIndexName();
                }
                changeSqlList.add(sql);
            }
        }
    }

    public List<String> getChangeSqlList() {
        return changeSqlList;
    }
}
